#ifndef __ovip_third_nutshell_simple_bus__
#define __ovip_third_nutshell_simple_bus__
#include "xspcomm/xport.h"
#include <cstdint>

namespace ovip {
    class SimpleBusWrapper
    {
    public:
        // request_cmd
        u_int8_t cmd_read       = 0b0000;
        u_int8_t cmd_write      = 0b0001;
        u_int8_t cmd_readBurst  = 0b0010;
        u_int8_t cmd_writeBurst = 0b0011;
        u_int8_t cmd_writeLast  = 0b0111;
        u_int8_t cmd_probe      = 0b1000;
        u_int8_t cmd_prefetch   = 0b0100;
        // response_cmd
        uint8_t cmd_readLast  = 0b0110;
        uint8_t cmd_writeResp = 0b0101;
        uint8_t cmd_probeHit  = 0b1100;
        uint8_t cmd_probMiss  = 0b1000;
        // ports
        xspcomm::XPort port;
        SimpleBusWrapper(xspcomm::XPort &port, std::string prefix = "")
        {
            this->port = port.NewSubPort(prefix);
        }
        bool IsReqReady() { return this->port["req_ready"] == 1; }
        void ReqSetValid() { this->port["req_valid"] = 1; }
        void ReqUnValid() { this->port["req_valid"] = 0; }
        u_int64_t ReqReadData(u_int32_t addr)
        {
            this->port["resp_ready"]    = 1;
            this->port["req_bits_user"] = 0x123;
            this->port["req_bits_addr"] = addr;
            this->port["req_bits_size"] = 7;
            this->port["req_bits_cmd"]  = this->cmd_read;
            return (u_int64_t)this->port["resp_bits_rdata"];
        }
        bool ReqWriteData(u_int32_t addr, u_int64_t data, unsigned char mask)
        {
            this->port["resp_ready"]     = 1;
            this->port["req_bits_addr"]  = addr;
            this->port["req_bits_size"]  = 7;
            this->port["req_bits_cmd"]   = this->cmd_write;
            this->port["req_bits_wmask"] = mask;
            this->port["req_bits_wdata"] = data;
            return true;
        }
        bool RespWriteData(u_int32_t cmd, u_int64_t data)
        {
            this->port["resp_valid"]      = 1;
            this->port["resp_bits_cmd"]   = cmd;
            this->port["resp_bits_rdata"] = data;
            return true;
        }
        bool RespReadData(u_int32_t cmd, u_int64_t data)
        {
            return this->RespWriteData(cmd, data);
        }
        u_int64_t RespData() { return this->port["resp_bits_rdata"]; }
        bool IsRespReady() { return this->port["resp_ready"] == 1; }
        bool IsReqValid() { return this->port["req_valid"] == 1; }
        bool IsRespValid() { return this->port["resp_valid"] == 1; }
        bool IsRespWriteCmp()
        {
            return this->port["resp_bits_cmd"] == this->cmd_writeResp;
        }

        bool IsReqRead()
        {
            return this->port["req_bits_cmd"] == this->cmd_read
                   && this->IsReqValid();
        }
        bool IsReqReadBurst()
        {
            return this->port["req_bits_cmd"] == this->cmd_readBurst
                   && this->IsReqValid();
        }
        bool IsReqWrite()
        {
            return this->port["req_bits_cmd"] == this->cmd_write
                   && this->IsReqValid();
        }
        bool IsReqWriteBurst()
        {
            return this->port["req_bits_cmd"] == this->cmd_writeBurst
                   && this->IsReqValid();
        }
        bool IsReqWriteLast()
        {
            return this->port["req_bits_cmd"] == this->cmd_writeLast
                   && this->IsReqValid();
        }

        void Zero() { this->port.SetZero(); }
    };
} // namespace ovip

#endif
